package org.kernely.stream.userpage;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.Map.Entry;

import org.kernely.security.persistence.Role;
import org.kernely.security.persistence.User;
import org.kernely.stream.StreamBundle;
import org.kernely.stream.dao.StreamDAO;
import org.kernely.stream.persistence.Stream;
import org.kernely.ui.mvp.KernelyPresenter;
import org.kernely.ui.utils.KernelyNotification;

import com.vaadin.event.ItemClickEvent;
import com.vaadin.event.ItemClickEvent.ItemClickListener;
import com.vaadin.terminal.ExternalResource;
import com.vaadin.terminal.Resource;
import com.vaadin.ui.Button;
import com.vaadin.ui.Tree;
import com.vaadin.ui.Window;
import com.vaadin.ui.Button.ClickEvent;

/**
 *	Presenter of the user settings of streams, to change subscriptions.
 */
public class StreamSettingsWindowPresenter extends KernelyPresenter<StreamSettingsWindowView>{

	private static ExternalResource SUBSCRIBED_ICON = new ExternalResource("/streambundle/images/stream_subscribed.png");
	private static ExternalResource UNSUBSCRIBED_ICON = new ExternalResource("/streambundle/images/stream_blank.png");


	/**
	 * @see org.kernely.ui.mvp.KernelyPresenter#bind()
	 */
	@SuppressWarnings("serial")
	public void bind() {
		// Get categories and streams
		HashMap<String, Set<Stream>> map = new HashMap<String, Set<Stream>>();
		StreamDAO sdao = StreamDAO.getInstance();
		Set<Stream> streams = sdao.getAllStream();
		for (Stream stream : streams){
			//A user can only see streams he can subscribes (or if he is administrator)
			boolean isAdmin = StreamBundle.getSecurityService().currentUserHasOneOf(Role.ROLE_ADMINISTRATOR);
			boolean hasRights = StreamBundle.getSecurityService().currentUserHasPermission(stream.getCategory()+":subscribe:"+stream.getUid());
			if (isAdmin || hasRights){
				//Add the stream
				String[] categorySplit = stream.getCategory().split("/"); 
				String categoryName = this.capitalize(categorySplit[1]); // [0] =  "stream", [1] = category

				// Add the category if the category does'nt exists
				if (! map.containsKey(categoryName)){
					HashSet<Stream> set = new HashSet<Stream>();
					set.add(stream);
					map.put(categoryName, set);
				} else {
					// Add the stream to the convenient category
					Set<Stream> set = map.get(categoryName);
					set.add(stream);
				}				
			}
		}

		// Fill the tree
		Tree tree = view.getSubscriptionsTree();
		boolean atLeastOneSubscription = false; // Used to develop a category if the user has subscribed to one stream in the category
		for (Entry<String, Set<Stream>> entry : map.entrySet()){
			String key = entry.getKey();
			tree.addItem(key);
			tree.setItemCaption(key, key);
			tree.setChildrenAllowed(key, true);

			// Add all the streams in this category
			for (Stream stream : entry.getValue()){
				tree.addItem(stream);
				tree.setParent(stream,key);
				tree.setChildrenAllowed(stream, false);
				tree.setItemCaption(stream, stream.getTitle());

				// The icon change if the user has subscribed.
				if (stream.getSubscriptors().contains(StreamBundle.getSecurityService().getCurrentUser())){
					tree.setItemIcon(stream, SUBSCRIBED_ICON);
					atLeastOneSubscription = true;
				} else {
					tree.setItemIcon(stream, UNSUBSCRIBED_ICON);
				}
			}
			if (atLeastOneSubscription){
				tree.expandItem(key);
			}


		}

		// Add a listener to the tree
		this.view.getSubscriptionsTree().addListener(new ItemClickListener(){

			/**
			 * Called when a user click on the tree.
			 */
			public void itemClick(ItemClickEvent event) {
				if (event.getButton() == ItemClickEvent.BUTTON_LEFT){

					// If the selected item is a stream, modify it icon
					if (event.getItemId() instanceof Stream ){
						Resource actualIcon = view.getSubscriptionsTree().getItemIcon(event.getItemId());
						if (actualIcon.equals(SUBSCRIBED_ICON)){
							view.getSubscriptionsTree().setItemIcon(event.getItemId(), UNSUBSCRIBED_ICON);							
						} else {
							view.getSubscriptionsTree().setItemIcon(event.getItemId(), SUBSCRIBED_ICON);							
						}
					}
					view.getSubscriptionsTree().setValue(event.getItemId());
				}
			}
		});

		//Add a listener on the save button
		this.view.getSaveButton().addListener(new Button.ClickListener(){

			/**
			 * Action performed when the button is clicked.
			 */
			public void buttonClick(ClickEvent event) {
				save();				
			}
			
		});
		
	}

	private String capitalize(String string){
		char[] char_table = string.toCharArray();
		char_table[0]=Character.toUpperCase(char_table[0]);
		return new String(char_table);
	}
	
	private void save(){
		StreamDAO sdao = StreamDAO.getInstance();
		User current = StreamBundle.getSecurityService().getCurrentUser();

		for (Object itemId : this.view.getSubscriptionsTree().getItemIds()){
			// We consider only leafs (streams)
			if (itemId instanceof Stream){
				Stream stream = (Stream) itemId;
				Resource icon = view.getSubscriptionsTree().getItemIcon(itemId);
				Set<User> subscriptors = stream.getSubscriptors();
				// Add or remove the current user in subscriptors set
				if (icon.equals(SUBSCRIBED_ICON)){
					subscriptors.add(current);
				} else {
					subscriptors.remove(current);
				}
				// TODO Fix Exception 2 sessions opened!
				sdao.updateStream(stream);
			}
		}
		
		// Force the StreamUserPage to actualize.
		StreamBundle.getEventBus().broadcastEvent(new StreamMustDisplayMessagesEvent(this));

		view.getWindow().getParent().showNotification((new KernelyNotification("Subscriptions successfully updated.", KernelyNotification.INFO_ICON)));

		Window win = (Window)view.getParent();
		win.getParent().removeWindow(win);
	}
}
